package com.deer.wms.intercept.filter;

import cn.hutool.core.util.ObjectUtil;
import com.deer.wms.intercept.common.data.CommonDataService;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.intercept.security.JwtUtil;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.core.result.ResultGenerator;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.util.RedisUtil;
import com.deer.wms.project.root.util.ResponseUtil;
import com.deer.wms.project.root.util.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 登录会调用springSecurity的登录方法进行验证
 * <p>
 * ===== 登录成功
 * http状态status状态返回200，并且自定义响应状态code返回200，响应头存放token，key = token，value = jwt生成的token内容
 * </p>
 * <p>
 * ===== 登录失败
 * http状态status状态返回401，并且自定义响应状态code返回401，并提示对应的内容
 * </p>
 * <p>
 * ===== 权限不足
 * http状态status状态返回403，并且自定义响应状态code返回403，并提示对应的内容
 * </p>
 *
 * @author : wei
 * @since : 2021-07-30 15:14:14
 **/
public class TokenAuthFilter extends BasicAuthenticationFilter {
    private JwtUtil jwtUtil;
    private RedisUtil redisUtil;
    private CommonDataService commonDataService;

    public TokenAuthFilter(AuthenticationManager authenticationManager, JwtUtil jwtUtil, RedisUtil redisUtil, CommonDataService commonDataService) {
        super(authenticationManager);
        this.jwtUtil = jwtUtil;
        this.redisUtil = redisUtil;
        this.commonDataService = commonDataService;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException,
            ServletException, ServiceException {
        //获取当前认证成功用户的权限信息
        UsernamePasswordAuthenticationToken authentication = null;

        try {
            authentication = getAuthentication(request, response);
            //判断有权限信息，放到权限上下文中
            if (authentication != null) {
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
            chain.doFilter(request, response);
        } catch (ServiceException e) {
            ResponseUtil.out(response, ResultGenerator.genFailResult(CommonCode.TOKEN_INVALID));
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    /**
     * 验证token是否过期； 是否即将过期，若即将过期则刷新token
     *
     * @param token
     * @return
     */
    private String validToken(String token) {
        //判断token是否过期
        if (JwtUtil.isExpiration(token)) {
            throw new ServiceException(CommonCode.TOKEN_INVALID);
        }
        //判断token是否即将过期，若将要过期则刷新
        if (JwtUtil.isToBeExpiration(token)) {
            String username = jwtUtil.getUsername(token);
//            commonDataService.removeCurrentUserDataFromRedis(token);
            String newToken = jwtUtil.generateToken(username);
            return newToken;
        }
        return null;
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //从header获取token
        String token = request.getHeader("access-token");
        if (StringUtils.isNotEmpty(token)) {
//            CurrentUser currentUser = commonDataService.getCurrentUserDataFromRedis(token);
//            String tempToken = validToken(token);
//            String newToken = StringUtils.isNotEmpty(tempToken) ? tempToken : token;
            //先判断是否已经过期，再判断是否即将过期
            //从token获取用户名
            String username = jwtUtil.getUsername(token);
            Object o = redisUtil.get(username);
            if (ObjectUtil.isNull(o)) {
                throw new ServiceException(CommonCode.TOKEN_INVALID);
            }

            //临近一小时有操作则延期
            if (redisUtil.getExpireTime(username) < 60L * 60) {
                redisUtil.updateExprieTime(username, 60L * 60 * 24);
            }

            //从redis获取对应权限列表
            List<String> permissionValueList = (List<String>) o;
            Collection<GrantedAuthority> authority = new ArrayList<>();
            for (String permissionValue : permissionValueList) {
                if (StringUtils.isEmpty(permissionValue)) {
                    continue;
                }
                SimpleGrantedAuthority auth = new SimpleGrantedAuthority(permissionValue);
                authority.add(auth);
            }
            //判断是否需要刷新token，需要的话则将新的token放置于reponse的Header中
//            if (StringUtils.isNotEmpty(tempToken)) {
//                response.setHeader("Access-Control-Expose-Headers", "access-token");
//                response.addHeader("access-token", newToken);
//            }
            return new UsernamePasswordAuthenticationToken(username, token, authority);
        }
        return null;
    }
}
